/*
 * radio.cpp - FM radio GUI
 *
 * Copyright (C) 2010-2011 Serge Begger
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "radio.h"
#include "ui_radio.h"

Radio::Radio(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Radio)
{
    ui->setupUi(this);
    stationList1 = new QList<float>;
    stationList2 = new QList<float>;
    stationList3 = new QList<float>;
    freqPanel = new numPanel(this,true,QRect(0,90,300,400));
    freqPanel->helpLabel->setText("FREQ: 66 - 108 Mhz");
    connect(freqPanel, SIGNAL(putFreq()), this, SLOT(updateUiFreq()));
    connect(freqPanel, SIGNAL(endPutFreq()), this, SLOT(setManFreq()));
    settings = new QSettings("carpc", "fmradio", this);
    settings->setPath(QSettings::IniFormat,QSettings::UserScope,"carpc");

    min_freq = 66.00;
    max_freq = 108.00;
    currSignal = 0;
    resetCount();
    currFreq = min_freq;

    //Load settings
    loadStation();

    currVolume = settings->value("currVolume").toInt();
    stationRange = settings->value("stationRange").toInt();
    currStation = settings->value("currStation").toInt();
    if (currStation == 0) currStation = 1;
    currBand = settings->value("currBand").toInt();
    if (currBand == 0) currBand = 1;
    currFreq = returnFreq();
    if (currFreq == 0) currFreq = min_freq;

    updateStButton();

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateGUI()));

    scanTimer = new QTimer(this);
    connect(scanTimer, SIGNAL(timeout()), this, SLOT(startScan()));

    seekTimer = new QTimer(this);
    connect(seekTimer, SIGNAL(timeout()), this, SLOT(autoSeekStation()));

    gstEngine = new gstengine(this);
}

Radio::~Radio()
{
    tuner.closeTuner();
    gstEngine->~gstengine();
    delete ui;
}

bool Radio::initRadio()
{
    settingsGlobal = new QSettings("carpc", "general", this);
    settingsGlobal->setPath(QSettings::IniFormat,QSettings::UserScope,"carpc");

    QString fmDevName = settingsGlobal->value("fmdevpath").toString();

    if (fmDevName.isEmpty()) {
        delete ui;
        return false;
    }

    if(!tuner.initTuner(fmDevName)) {
        ui->typeSignalLabel->setText("NO TUNER");
    }

    if (!gstEngine->loopaudio()) {
        delete ui;
        return false;
    }

    setVolume(currVolume);

    if(!timer->isActive()){
         timer->start (100);
    }

    setTunerFreq();
    updateGUI();
    return true;
}

void Radio::setVolume(int vol) {
    currVolume = vol;
    gstEngine->setVolume(vol);
    settings->setValue("currVolume"  , currVolume);
}

void Radio::on_backButton_pressed()
{
    emit hideWidget();
}

void Radio::on_closeButton_pressed()
{
    this->~Radio();
}

void Radio::changeEvent(QEvent *e)
{
    QWidget::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void Radio::on_startScanButton_clicked()
{
    if(scanTimer->isActive())
    {
        return;
    }

    currFreq = min_freq;
    currStation = 1;
    stationRange = 0;
    updateStButton();

    if(!scanTimer->isActive()){
        scanTimer->start(100);
    }
}

void Radio::on_seekLeftButton_pressed()
{
    currButton = ui->seekLeftButton;
    range = -1;
    startTimer();
}

void Radio::on_seekRightButton_pressed()
{
    currButton = ui->seekRightButton;
    range = 1;
    startTimer();
}

void Radio::on_stationButton1_pressed()
{
    currButton = ui->stationButton1;
    currStation = 1 + stationRange;
    startTimer();
}

void Radio::on_stationButton2_pressed()
{
    currButton = ui->stationButton2;
    currStation = 2 + stationRange;
    startTimer();
}

void Radio::on_stationButton3_pressed()
{
    currButton = ui->stationButton3;
    currStation = 3 + stationRange;
    startTimer();
}

void Radio::on_stationButton4_pressed()
{
    currButton = ui->stationButton4;
    currStation = 4 + stationRange;
    startTimer();
}

void Radio::on_stationButton5_pressed()
{
    currButton = ui->stationButton5;
    currStation = 5 + stationRange;
    startTimer();
}

void Radio::on_stationButton6_pressed()
{
    currButton = ui->stationButton6;
    currStation = 6 + stationRange;
    startTimer();
}

void Radio::on_stationLeftButton_pressed()
{
    if (stationRange > 0) {
        stationRange = stationRange - 6;
        updateStButton();
    }
}

void Radio::on_stationRightButton_pressed()
{
    int temp = 6*(stationRange+1) + 1;
    if (temp <= stCount()) {
        stationRange = stationRange + 6;
        updateStButton();
    }
}

void Radio::on_setBandButton_pressed()
{
    currBand = currBand + 1;
    if (currBand > 3) currBand = 1;
    currStation = 1;
    stationRange = 0;
    updateStButton();
    currFreq = returnFreq();
    if (currFreq == 0) currFreq = min_freq;
    setTunerFreq();
}

void Radio::on_setFreqButton_pressed()
{
    bool frPanVis = freqPanel->isVisible();

    if (!frPanVis)
        freqPanel->onShow();
    else
        freqPanel->offShow();

    ui->bandLcd->setVisible(frPanVis);
    ui->labelFM->setVisible(frPanVis);
    ui->typeSignalLabel->setVisible(frPanVis);
}

void Radio::setManFreq()
{
    float tempFreq = freqPanel->freq->toFloat();
    if (tempFreq >= min_freq && tempFreq <= max_freq) {
        currFreq = tempFreq;
        setTunerFreq();
    }
    ui->bandLcd->setVisible(true);
    ui->labelFM->setVisible(true);
    ui->typeSignalLabel->setVisible(true);
}

void Radio::startTimer()
{
    QTimer::singleShot(300, this, SLOT(endTimer()));
}

void Radio::endTimer()
{
    if(seekTimer->isActive())  seekTimer->stop();
    if(scanTimer->isActive())  scanTimer->stop();
    if (currButton->objectName().contains("seek", Qt::CaseInsensitive)) {
        if (currButton->isDown()){
            seekTimer->start(100);
        } else {
            if(scanTimer->isActive()){
                scanTimer->stop();
                return;
            }
            seekStation();
        }
    } else if (currButton->objectName().contains("stationButton", Qt::CaseInsensitive)) {
        if (currButton->isDown()){
            insertFreq();
        } else {
            currFreq = returnFreq();
            setTunerFreq();
        }
    }
}

void Radio::startScan()
{
    gstEngine->mute(true);
    scanTimer->blockSignals(true);
    currFreq = currFreq + currStep;
    if(currFreq >max_freq)
    {
        currFreq = max_freq;
        scanTimer->stop();
        if(stCount()>0) {
            currStation = 1;
            currFreq = returnFreq();
            setTunerFreq();
        }
        updateGUI();
        saveStation();
        return;
    }
    tuner.setFreq(currFreq);
    int signal = 0;
    for (int i = 0; i < 3; i++) signal = signal + tuner.getSignal();
    signal = signal / 3;
    if (signal == 0)  {
      if (count2 > 3)
      {
        count3++;
        if (count3 > 20) resetCount();
      } else {
        count1++;
        if (startFreq == 0) {
            currStep = 0.01;
            startFreq = currFreq;
        }
        if (count1 > 20) resetCount();
      }
    } else {
      if (count1 > 7) count2++;
      if (count2 > 10) resetCount();
    }
    if (currFreq - startFreq > 0.5) resetCount();
    if (count1 > 7 && count2 > 3 && count3 > 3) {
        currFreq = currFreq - count3 * 0.01 - (count2 * 0.01 / 2);
        insertFreq();
        currStation++;
        resetCount();
    }
    scanTimer->blockSignals(false);
}

void Radio::resetCount()
{
    count1 = count2 = count3 = 0;
    startFreq = 0;
    currStep = 0.05;
}

void Radio::seekStation()
{
    currFreq = currFreq + 0.01 * range;
    if (currFreq > max_freq) {
        currFreq = max_freq;
    } else {
        if (currFreq < min_freq) {
            currFreq = min_freq;
        }
    }
    setTunerFreq();
}

void Radio::setTunerFreq()
{
    gstEngine->mute(true);
    QEventLoop loop; QTimer::singleShot(400, &loop, SLOT(quit())); loop.exec();
    tuner.setFreq(currFreq);
    settings->setValue("currStation",currStation);
    settings->setValue("currVolume",currVolume);
    QTimer::singleShot(400, &loop, SLOT(quit())); loop.exec();
    gstEngine->mute(false);
}

void Radio::autoSeekStation()
{
    gstEngine->mute(true);
    float step = 0.05;
    currFreq = currFreq + step * range;
    if (currFreq > max_freq) {
        currFreq = max_freq;
    } else {
        if (currFreq < min_freq) {
            currFreq = min_freq;
        }
    }
    tuner.setFreq(currFreq);
    int signal = 0;
    for (int i = 0; i < 3; i++) signal = signal + tuner.getSignal();
    signal = signal / 3;
    if (signal == 0)  {
      if (count2 > 3)
      {
        count3++;
        if (count3 > 20) resetCount();
      } else {
        count1++;
        if (startFreq == 0) {
            currStep = 0.01;
            startFreq = currFreq;
        }
        if (count1 > 20) resetCount();
      }
    } else {
      if (count1 > 7) count2++;
      if (count2 > 10) resetCount();
    }
    if (currFreq - startFreq > 0.5) resetCount();
    if (count1 > 7 && count2 > 3 && count3 > 3) {
        currFreq = currFreq - count3 * 0.01 - (count2 * 0.01 / 2);
            seekTimer->stop();
            gstEngine->mute(false);
    }
}

void Radio::updateGUI()
{
    if(!freqPanel->isVisible())
        ui->freqencyLcd->display(QString::number(currFreq,'f',2));

    ui->bandLcd->display(QString::number(currBand)+QString("-%1").arg(currStation, 2, 10, QChar('0')));
    currSignal = tuner.getSignal();
    if (currSignal == 0) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-00.svg")));
    if(currSignal > 0 && currSignal <= 10) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-01.svg")));
    if(currSignal > 10 && currSignal <= 20) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-02.svg")));
    if(currSignal > 20 && currSignal <= 30) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-03.svg")));
    if(currSignal > 30 && currSignal <= 40) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-04.svg")));
    if(currSignal > 40 && currSignal <= 50) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-05.svg")));
    if(currSignal > 50 && currSignal <= 60) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-06.svg")));
    if(currSignal > 60 && currSignal <= 70) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-07.svg")));
    if(currSignal > 70 && currSignal <= 80) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-08.svg")));
    if(currSignal > 80 && currSignal <= 90) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-09.svg")));
    if(currSignal > 90) ui->signalLabel->setPixmap(QPixmap(QString::fromUtf8(":/sig/res/signal-10.svg")));

    //update stereo
    int stereo = tuner.getStereo();
    if(stereo == 1) ui->typeSignalLabel->setText("STEREO");
    else if (stereo == 0) ui->typeSignalLabel->setText("");

}

void Radio::updateUiFreq()
{
    ui->freqencyLcd->display(freqPanel->freq->toFloat());
}

void Radio::updateStButton()
{
    ui->stationButton1->setText(QString::number(1 + stationRange));
    ui->stationButton2->setText(QString::number(2 + stationRange));
    ui->stationButton3->setText(QString::number(3 + stationRange));
    ui->stationButton4->setText(QString::number(4 + stationRange));
    ui->stationButton5->setText(QString::number(5 + stationRange));
    ui->stationButton6->setText(QString::number(6 + stationRange));
    settings->setValue("stationRange",stationRange);
    settings->setValue("currBand",currBand);
}

void Radio::saveStation()
{
    settings->beginWriteArray("StationList1");
    for (int i=0; i < stationList1->size(); i++) {
        settings->setArrayIndex(i);
        settings->setValue("freq", QString::number(stationList1->at(i)));
    }
    settings->endArray();

    settings->beginWriteArray("StationList2");
    for (int i=0; i < stationList2->size(); i++) {
        settings->setArrayIndex(i);
        settings->setValue("freq", QString::number(stationList2->at(i)));
    }
    settings->endArray();

    settings->beginWriteArray("StationList3");
    for (int i=0; i < stationList3->size(); i++) {
        settings->setArrayIndex(i);
        settings->setValue("freq", QString::number(stationList3->at(i)));
    }
    settings->endArray();
}

void Radio::loadStation()
{
    int size1 = settings->beginReadArray("StationList1");
    for (int i=0; i < size1; i++) {
        settings->setArrayIndex(i);
        stationList1->insert(i, settings->value("freq").toFloat());
    }
    settings->endArray();

    int size2 = settings->beginReadArray("StationList2");
    for (int i=0; i < size2; i++) {
        settings->setArrayIndex(i);
        stationList2->insert(i, settings->value("freq").toFloat());
    }
    settings->endArray();

    int size3 = settings->beginReadArray("StationList3");
    for (int i=0; i < size3; i++) {
        settings->setArrayIndex(i);
        stationList3->insert(i, settings->value("freq").toFloat());
    }
    settings->endArray();
}

float Radio::returnFreq()
{
    float tempFreq = currFreq;
    switch (currBand) {
        case 1:
            if(stationList1->count() >= currStation)
                tempFreq = stationList1->at(currStation-1);
            break;
        case 2:
            if(stationList2->count() >= currStation)
                tempFreq = stationList2->at(currStation-1);
            break;
        case 3:
            if(stationList3->count() >= currStation)
                tempFreq = stationList3->at(currStation-1);
            break;
        }
    if (tempFreq == 0) tempFreq = min_freq;
    return tempFreq;
}

void Radio::insertFreq()
{
    switch (currBand) {
    case 1:
        stationList1->insert(currStation-1,currFreq);
        break;
    case 2:
        stationList2->insert(currStation-1,currFreq);
        break;
    case 3:
        stationList3->insert(currStation-1,currFreq);
        break;
    }
    saveStation();
}

int Radio::stCount()
{
    int count = 0;
    switch (currBand) {
    case 1:
        count = stationList1->size();
        break;
    case 2:
        count = stationList2->size();
        break;
    case 3:
        count = stationList3->size();
        break;
    }
    return count;
}

